home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1998 / MacHack 1998.toast / Programming Contest / ~Solutions Submitted / Problem 04 - Three and One fix / Solution.cp < prev    next >
Encoding:
Text File  |  1998-06-19  |  8.8 KB  |  320 lines  |  [TEXT/CWIE]

  1. /*
  2. Problem 04 - Text Processing
  3.  
  4. const
  5.     kMaxHandleSize = 1000000;
  6. const
  7.     kActionMove = 1;
  8.     kActionInsert = 2;
  9.     kActionDelete = 3;
  10.     kActionSearch = 4;
  11.     kActionSearchAndReplace = 5;
  12. const
  13.     kFlagCaseSensitiveBit = 0;
  14.     kFlagGlobalBit = 1;
  15.     kFlagBackwardsBit = 2;
  16. type
  17.   ActionRecord = record
  18.     action: UInt32;
  19.     amount: SInt32;
  20.     flags: UInt32;
  21.     search: Str255;
  22.     replace: Str255;
  23.   end;
  24.   ActionRecordArray = array[0..0] of ActionRecord;
  25.   ActionRecordArrayPtr = ^ActionRecordArray;
  26.  
  27. procedure TextProcess( data: Handle; action_count: UInt32; actions:
  28. ActionRecordArrayPtr );
  29.  
  30. Given an unlocked handle to a block of text, you need to apply a sequence of
  31. actions to the data.  You will be required to insert text, delete text, search
  32. for text, search for and replace text.  All required actions take place at the
  33. position of the current selection pointer, which starts at zero, before the
  34. first character in the data.  In response to each of the action commands you
  35. need to perform the following:
  36.  
  37. kActionMove - move the internal position forward by the amount field (which may
  38. be negative).  (Example, kActionMove with amount set to kMaxHandleSize will set
  39. the internal pointer to be GetHandleSize( data )).
  40.  
  41. kActionInsert - Insert the replace string at the current location.  (Example,
  42. if the internal pointer is GetHandleSize( data ), then the replace string will
  43. be appended to the handle.
  44.  
  45. kActionDelete - Delete the number of characters specified by the amount field. 
  46. The internal position pointer is never moved.  If the amount field is greater
  47. than the number of characters after the internal pointer, then fewer characters
  48. are deleted such that the handle is truncated at the current value of the
  49. selection pointer.
  50.  
  51. kActionSearch - search forward (backwards if the kFlagBackwardsBit is set in
  52. the flags field) for the search field (case sensitively if the
  53. kFlagCaseSenstitiveBit is set in the flags field).  The position pointer should
  54. be set to point before the first character of the string if it is found, or at
  55. GetHandleSize (zero if backwards) if not found.  If there is a match at the
  56. initial position, it is not counted (ie, kActionMove -kMaxHandleSize, kSearch
  57. 'hello', kSearch 'hello' finds the second occurance of 'hello').
  58.  
  59. kActionSearchAndReplace - search forward (or backward if the kFlagBackwardsBit
  60. is set in the flags field), but when a match is found, replace it with the
  61. replace string, leaving the position pointer unmoved.  If the kFlagGlobalBit is
  62. set in the flags field, continue searching as long matches continues to be
  63. found.  Repeated searches begin after the previous replace string (i.e., never
  64. replace any characters of the replace string).  For example, if you replace
  65. 'aaa' with 'ABA' (case insensitively) in 'aaaaaaaa' you will get 'ABAABAaa',
  66. not 'ABABABAa'.  Replace never moves the internal position pointer.
  67.  
  68. The internal selection pointer is constrained to be in the range of 0 and
  69. GetHandleSize(data), inclusive, at all times.  Should any action cause the
  70. selection pointer to become less than zero (or greater than GetHandleSize),
  71. then you must reset it to zero (or GetHandleSize, respectively).  The handle
  72. size will never exceed 1 Meg, and you will have plenty of memory to play with.  
  73.  
  74. Characters from chr(127)-chr(255) will never appear in the handle or any
  75. strings.  
  76. */
  77.  
  78. #include "Solution.h"
  79. #include <string.h>
  80. #include <ctype.h>
  81.  
  82. // Fill in your solution and then submit this folder
  83.  
  84. // Team Name: FILL IN YOUR TEAM NAME!
  85.  
  86. static void
  87. DoMove(Handle, const ActionRecord& action, int& selection)
  88. {
  89.     selection += action.amount;
  90. }
  91.  
  92. static void
  93. SimpleInsert(Handle data, int selection, int amount, const void* insertData)
  94. {
  95.     int size = GetHandleSize(data);
  96.     SetHandleSize(data, size + amount);
  97.     BlockMove(*data + selection, *data + selection + amount, size - selection);
  98.     BlockMove(insertData, *data + selection, amount);
  99. }
  100.  
  101. static void
  102. DoInsert(Handle data, const ActionRecord& action, int &selection)
  103. {
  104.     SimpleInsert(data, selection, action.search[0], &action.search[1]);
  105.     //selection += action.search[0];
  106. }
  107.  
  108. static void
  109. SimpleDelete(Handle data, int selection, int amount)
  110. {
  111.     int size = GetHandleSize(data);
  112.     if (selection + amount > size)
  113.         amount = size - selection;
  114.     BlockMove(*data + selection + amount, *data + selection, size - amount - selection);
  115.     SetHandleSize(data, size - amount);
  116. }
  117.  
  118. static void
  119. DoDelete(Handle data, const ActionRecord& action, int selection)
  120. {
  121.     SimpleDelete(data, selection, action.amount);
  122. }
  123.  
  124. static bool
  125. MatchCaseInsensitive(const char *a, const char *b, int length)
  126. {
  127.     while (length-- != 0)
  128.         if (tolower(*a++) != tolower(*b++))
  129.             return false;
  130.     return true;
  131. }
  132.  
  133. static bool
  134. Match(Handle data, const ActionRecord& action, int position)
  135. {
  136.     if (GetHandleSize(data) - position < action.search[0])
  137.         return false;
  138.     if (action.flags & (1 << kFlagCaseSenstitiveBit))
  139.         return memcmp(*data + position, &action.search[1], action.search[0]) == 0;
  140.     return MatchCaseInsensitive(*data + position, (char *)&action.search[1], action.search[0]);
  141. }
  142.  
  143. static void
  144. Replace(Handle data, const ActionRecord& action, int position)
  145. {
  146.     SimpleDelete(data, position, action.search[0]);
  147.     SimpleInsert(data, position, action.replace[0], &action.replace[1]);
  148. }
  149.  
  150. static void
  151. DoSearchForward(Handle data, const ActionRecord& action, int& selection)
  152. {
  153.     while (1) {
  154.         if (selection == GetHandleSize(data))
  155.             return;
  156.         selection += 1;
  157.         if (Match(data, action, selection))
  158.             return;
  159.     }
  160. }
  161.  
  162. static void
  163. DoSearchBackward(Handle data, const ActionRecord& action, int& selection)
  164. {
  165.     while (1) {
  166.         if (selection == 0)
  167.             return;
  168.         selection -= 1;
  169.         if (Match(data, action, selection))
  170.             return;
  171.     }
  172. }
  173.  
  174. static void
  175. DoSearch(Handle data, const ActionRecord& action, int& selection)
  176. {
  177.     if (action.flags & (1 << kFlagBackwardsBit))
  178.         DoSearchBackward(data, action, selection);
  179.     else
  180.         DoSearchForward(data, action, selection);
  181. }
  182.  
  183. /*
  184.  
  185. kActionSearchAndReplace - search forward (or backward if the kFlagBackwardsBit
  186. is set in the flags field), but when a match is found, replace it with the
  187. replace string, leaving the position pointer unmoved.  If the kFlagGlobalBit is
  188. set in the flags field, continue searching as long matches continues to be
  189. found.  Repeated searches begin after the previous replace string (i.e., never
  190. replace any characters of the replace string).  For example, if you replace
  191. 'aaa' with 'ABA' (case insensitively) in 'aaaaaaaa' you will get 'ABAABAaa',
  192. not 'ABABABAa'.  Replace never moves the internal position pointer.
  193.  
  194. */
  195.  
  196. static void
  197. DoReplaceForward(Handle data, const ActionRecord& action, int& selection)
  198. {
  199.     while (1) {
  200.         if (selection >= GetHandleSize(data))
  201.             return;
  202.         selection += 1;
  203.         if (Match(data, action, selection)) {
  204.             Replace(data, action, selection);
  205.             if ((action.flags & (1 << kFlagGlobalBit)) == 0)
  206.                 return;
  207.             selection += action.search[0] - 1;
  208.         }
  209.     }
  210. }
  211.  
  212. static void
  213. DoReplaceBackward(Handle data, const ActionRecord& action, int& selection)
  214. {
  215.     while (1) {
  216.         if (selection <= 0)
  217.             return;
  218.         selection -= 1;
  219.         if (Match(data, action, selection)) {
  220.             Replace(data, action, selection);
  221.             if ((action.flags & (1 << kFlagGlobalBit)) == 0)
  222.                 return;
  223.             selection -= action.search[0] - 1;
  224.         }
  225.     }
  226. }
  227.  
  228. static void
  229. DoSearchAndReplace(Handle data, const ActionRecord& action, int& selection)
  230. {
  231.     if (action.flags & (1 << kFlagBackwardsBit))
  232.         DoReplaceBackward(data, action, selection);
  233.     else
  234.         DoReplaceForward(data, action, selection);
  235. }
  236.  
  237. static void
  238. DumpHandle(Handle data)
  239. {
  240.     int size = GetHandleSize(data);
  241.     for (int i = 0; i < size; i++) {
  242.         char c((*data)[i]);
  243.         if (c == 13)
  244.             printf("\n");
  245.         else
  246.             printf("%c", c);
  247.     }
  248. }
  249.  
  250. static void
  251. DumpState(Handle data, const ActionRecord& action, int& selection)
  252. {
  253.     switch (action.action) {
  254.         case kActionMove:
  255.             printf("move");
  256.             break;
  257.         
  258.         case kActionInsert:
  259.             printf("insert");
  260.             break;
  261.         
  262.         case kActionDelete:
  263.             printf("delete");
  264.             break;
  265.             
  266.         case kActionSearch:
  267.             printf("search");
  268.             break;
  269.         
  270.         case kActionSearchAndReplace:
  271.             printf("search and replace");
  272.             break;
  273.     }
  274.     printf(": |");
  275.     DumpHandle(data);
  276.     printf("|\nselection is now %d\n", selection);
  277. }
  278.  
  279. static void
  280. DoAction(Handle data, const ActionRecord& action, int& selection)
  281. {
  282.     switch (action.action) {
  283.         case kActionMove:
  284.             DoMove(data, action, selection);
  285.             break;
  286.         
  287.         case kActionInsert:
  288.             DoInsert(data, action, selection);
  289.             break;
  290.         
  291.         case kActionDelete:
  292.             DoDelete(data, action, selection);
  293.             break;
  294.             
  295.         case kActionSearch:
  296.             DoSearch(data, action, selection);
  297.             break;
  298.         
  299.         case kActionSearchAndReplace:
  300.             DoSearchAndReplace(data, action, selection);
  301.             break;
  302.     }
  303.     
  304.     if (selection < 0)
  305.         selection = 0;
  306.     if (selection > GetHandleSize(data))
  307.         selection = GetHandleSize(data);
  308.         
  309.     //DumpState(data, action, selection);
  310. }
  311.  
  312. pascal void TextProcess( Handle data, UInt32 action_count, ActionRecord *actions )
  313. {
  314.     //DumpHandle(data);
  315.     //printf("\n");
  316.     
  317.     int selection = 0;
  318.     for (int action = 0; action < action_count; action++)
  319.         DoAction(data, actions[action], selection);
  320. }